﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Activities;
using WFExtended.Activities;
using WFExtended.Tests.Model;
using System.Activities.Validation;
using WFExtended.Framework.ServiceModel;
using System.Collections.Generic;
using System.Activities.Statements;
using Microsoft.Activities.UnitTesting;
using Microsoft.QualityTools.Testing.Fakes;
using WFExtended.Framework.ServiceModel.Fakes;
using System.Runtime.Remoting.Messaging;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WFExtended.Tests.Activities
{
    [TestClass]
    public class WcfOperationInvokerTest
    {
        [TestMethod]
        public void WcfOperationInvokerBadOperationNameValidationTest()
        {
            DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

            ValidationResults result = ActivityValidationServices.Validate(new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker()
                    {
                        OperationName = "BadMethod",
                        Proxy = proxy
                    }
                }
            });

            Assert.IsNotNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Operation"));
        }

        [TestMethod]
        public void WcfOperationInvokerOperationValidationTest()
        {
            DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

            ValidationResults result = ActivityValidationServices.Validate(new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker()
                    {
                        OperationName = "Ping",
                        Proxy = proxy
                    }
                }
            });

            Assert.IsNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Operation"));
        }

        [TestMethod]
        public void WcfGenericOperationInvokerOperationValidationTest()
        {
            DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

            ValidationResults result = ActivityValidationServices.Validate(new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker<bool>()
                    {
                        OperationName = "CheckData",
                        Proxy = proxy
                    }
                }
            });

            Assert.IsNotNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Operation"));

            result = ActivityValidationServices.Validate(new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker<bool>()
                    {
                        OperationName = "CheckData",
                        Proxy = proxy,
                        Parameters = new Dictionary<string, InArgument>
                        {
                            {"data", new InArgument<MyData>()}
                        }
                    }
                }
            });

            Assert.IsNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Operation"));
        }

        [TestMethod]
        public void WcfOperationInvokerProxyValidationTest()
        {
            DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();
            DelegateInArgument<WcfProxy<IMockService2>> proxy2 = new DelegateInArgument<WcfProxy<IMockService2>>();

            ValidationResults result = ActivityValidationServices.Validate(new WcfOperationInvoker<bool>()
            {
                OperationName = "CheckData",
            });

            Assert.IsNotNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Proxy"));

           result = ActivityValidationServices.Validate(
            new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker<bool>()
                    {
                        OperationName = "CheckData",
                        Proxy = proxy
                    }
                }
            });

            Assert.IsNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Proxy"));


            result = ActivityValidationServices.Validate(
            new WcfConfigurationProxy<IMockService>()
            {
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new Sequence()
                    {
                        Activities =
                        {
                            new WcfConfigurationProxy<IMockService2>()
                            {
                                Body = new ActivityAction<WcfProxy<IMockService2>>()
                                {
                                    Argument = proxy2,
                                    Handler =  new WcfOperationInvoker()
                                    {
                                        OperationName = "Ping",
                                        Proxy = proxy
                                    }
                                }
                            },
                            new WcfOperationInvoker<bool>()
                            {
                                OperationName = "CheckData",
                                Proxy = proxy
                            }
                        }

                    }                  
                }
            });

            Assert.IsNull(result.Errors.SingleOrDefault((E) => E.PropertyName == "Proxy"));
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidWorkflowException))]
        public void WcfOperationInvoketWithoutArgumentExecutionTest()
        {
            DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

            var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService>()
            {
                ConfigurationName = "mockEndpoint",
                Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                {
                    Argument = proxy,
                    Handler = new WcfOperationInvoker<bool>()
                    {
                    }
                }
            });
            host.TestActivity();
        }

        [TestMethod]
        public void WcfOperationInvoketWithConfigurationStandardProxyExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService>()
                {
                    ConfigurationName = "mockEndpoint",
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker<bool>()
                        {
                            OperationName = "CheckData",
                            Proxy = proxy,
                            Parameters = new Dictionary<string, InArgument>
                            {
                            {"data", new InArgument<MyData>()}
                            }
                        }
                    }
                });

   
                host.TestActivity();

                Assert.AreEqual("CheckData", calledOperation);
            }

        }

        [TestMethod]
        public void WcfOperationInvoketWithConfigurationWebProxyExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService2>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                    {
                        calledOperation = M.Name;
                        return true;
                    };

                DelegateInArgument<WcfProxy<IMockService2>> proxy = new DelegateInArgument<WcfProxy<IMockService2>>();

                var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService2>()
                {
                    ChannelType = Framework.ServiceModel.ChannelType.Web,
                    ConfigurationName = "mockRestpoint",
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService2>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker()
                        {
                            OperationName = "Ping",
                            Proxy = proxy
                        }
                    }
                });

                host.TestActivity();

                Assert.AreEqual("Ping", calledOperation);
            }

        }

        [TestMethod]
        public void WcfOperationInvoketWithUriStandardProxyExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();                

                var host = WorkflowInvokerTest.Create(new WcfUriProxy<IMockService>()
                {
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker<bool>()
                        {
                            OperationName = "CheckData",
                            Proxy = proxy,
                            Parameters = new Dictionary<string, InArgument>
                            {
                            {"data", new InArgument<MyData>()}
                            }
                        }
                    }
                });

                host.InArguments.Binding = new BasicHttpBinding();
                host.InArguments.Uri = new Uri("http://localhost:8889");
                host.TestActivity();

                Assert.AreEqual("CheckData", calledOperation);
            }

        }

        [TestMethod]
        public void WcfOperationInvoketWithDiscoveryStandardProxyExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };


                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfDiscoveryProxy<IMockService>()
                {
                    ScopeMatch = DiscoveryScopeMatch.Prefix,
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker<bool>()
                        {
                            OperationName = "CheckData",
                            Proxy = proxy,
                            Parameters = new Dictionary<string, InArgument>
                            {
                            {"data", new InArgument<MyData>()}
                            }
                        }
                    }
                });

                host.InArguments.Binding = new BasicHttpBinding();
                host.TestActivity();

                Assert.AreEqual("CheckData", calledOperation);
            }

        }

        [TestMethod]
        [ExpectedException(typeof(Exception))]
        public void WcfOperationInvokeOnErrorWithNoRetryExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                MockService service = new MockService();

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return M.Invoke(service, C.InArgs);
                };
          

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService>()
                {
                    ConfigurationName = "mockEndpoint",
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker()
                        {
                            OperationName = "ValidateError",
                            Proxy = proxy
                        }
                    }
                });

                host.TestActivity();

            }

        }

        [TestMethod]
        public void WcfOperationInvokeOnErrorWithOneRetryExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                MockService service = new MockService();

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return M.Invoke(service, C.InArgs);
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService>()
                {
                    ConfigurationName = "mockEndpoint",
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker()
                        {
                            OperationName = "ValidateError",
                            Proxy = proxy
                        }
                    }
                });

                host.InArguments.RetryCount = 1;
                host.InArguments.RetryDelay = new TimeSpan(0, 0, 0, 0, 2);
                host.TestActivity();

            }

        }

        [TestMethod]
        public void WcfOperationInvoketNoPersistenceExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfUriProxy<IMockService>()
                {
                    EnablePersistence = false,
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker<bool>()
                        {
                            OperationName = "CheckData",
                            Proxy = proxy,
                            Parameters = new Dictionary<string, InArgument>
                            {
                            {"data", new InArgument<MyData>()}
                            }
                        }
                    }
                });

                host.InArguments.Binding = new BasicHttpBinding();
                host.InArguments.Uri = new Uri("http://localhost:8889");
                host.TestActivity();

                Assert.AreEqual("CheckData", calledOperation);
            }

        }

        [TestMethod]
        public void WcfOperationInvoketStandardBehaviorExecutionTest()
        {
            using (ShimsContext.Create())
            {
                MyEndPointBehavior myEndpointBehavior = new MyEndPointBehavior();
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfUriProxy<IMockService>()
                {
                    EnablePersistence = false,
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker<bool>()
                        {
                            OperationName = "CheckData",
                            Proxy = proxy,
                            Parameters = new Dictionary<string, InArgument>
                            {
                            {"data", new InArgument<MyData>()}
                            }
                        }
                    }
                });

                host.InArguments.Binding = new BasicHttpBinding();
                host.InArguments.Uri = new Uri("http://localhost:8889");
                host.TestActivity();

                Assert.AreEqual("CheckData", calledOperation);
                Assert.IsFalse(myEndpointBehavior.ValidateOK);

                host.InArguments.EndPointBehaviors = new List<IEndpointBehavior>
                    {
                          myEndpointBehavior
                    };
                host.TestActivity();

                Assert.IsTrue(myEndpointBehavior.ValidateOK);


            }

        }

        [TestMethod]
        public void WcfOperationInvoketWebBehaviorExecutionTest()
        {
            using (ShimsContext.Create())
            {
                MyEndPointBehavior myEndpointBehavior = new MyEndPointBehavior();
                string calledOperation = String.Empty;

                ShimExtendedProxy<IMockService2>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return true;
                };

                DelegateInArgument<WcfProxy<IMockService2>> proxy = new DelegateInArgument<WcfProxy<IMockService2>>();

                var host = WorkflowInvokerTest.Create(new WcfConfigurationProxy<IMockService2>()
                {
                    ConfigurationName = "mockRestpoint",
                    ChannelType = ChannelType.Web,
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService2>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker()
                        {
                            OperationName = "Ping",
                            Proxy = proxy
                        }
                    }
                });

                host.TestActivity();

                Assert.AreEqual("Ping", calledOperation);
                Assert.IsFalse(myEndpointBehavior.ValidateOK);

                host.InArguments.EndPointBehaviors = new List<IEndpointBehavior>
                    {
                          myEndpointBehavior
                    };
                host.TestActivity();

                Assert.IsTrue(myEndpointBehavior.ValidateOK);


            }

        }

        [TestMethod]
        public void WcfOperationInvokeDiscoveryExecutionTest()
        {
            using (ShimsContext.Create())
            {
                string calledOperation = String.Empty;

                MockService service = new MockService();

                ShimExtendedProxy<IMockService>.AllInstances.InvokeMethodInfoIMethodCallMessage = (P, M, C) =>
                {
                    calledOperation = M.Name;
                    return M.Invoke(service, C.InArgs);
                };

                DelegateInArgument<WcfProxy<IMockService>> proxy = new DelegateInArgument<WcfProxy<IMockService>>();

                var host = WorkflowInvokerTest.Create(new WcfDiscoveryProxy<IMockService>()
                {
                    MaxResults = 4,
                    Body = new System.Activities.ActivityAction<WcfProxy<IMockService>>()
                    {
                        Argument = proxy,
                        Handler = new WcfOperationInvoker()
                        {
                            OperationName = "Ping",
                            Proxy = proxy
                        }
                    }
                });

                host.InArguments.Binding = new BasicHttpBinding();
                host.InArguments.Timeout = new TimeSpan(0,0,0,0,2);
                host.InArguments.Scopes = new List<Uri>()
                {
                    new Uri("http://mock.wfe.com")
                };
                host.TestActivity();

                Assert.AreEqual("Ping", calledOperation);
            }

        }

    }
}
